package com.central.apps.util;

import cn.hutool.core.map.MapUtil;
import com.central.apps.service.OnlineEditService;
import org.apache.commons.io.IOUtils;
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * @author JHY
 */
@Service
public class FileUtil {


    @Autowired
    private OnlineEditService onlineEditService;

    /**
     * 前端下载文件方法
     *
     * @param name
     * @param filePath
     * @param response
     * @throws IOException
     */
    public static void downLoadFile(String filePath, String name, HttpServletResponse response) throws IOException {
        String path = filePath + "/" + name;
        System.out.println(" ===> downLoadFile - path:" + path);
        // path是指想要下载的文件的路径
        File file = new File(path);
        // 获取文件名
        String filename = file.getName();
        // 获取文件后缀名
        String ext = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
        System.out.println(" ===> downLoadFile - 文件后缀名：" + ext);

        // 将文件写入输入流
        FileInputStream fileInputStream = new FileInputStream(file);
        InputStream fis = new BufferedInputStream(fileInputStream);
        byte[] buffer = new byte[fis.available()];
        fis.read(buffer);
        fis.close();

        // 清空response
        response.reset();
        // 设置response的Header
        response.setCharacterEncoding("UTF-8");
        //Content-Disposition的作用：告知浏览器以何种方式显示响应返回的文件，用浏览器打开还是以附件的形式下载到本地保存
        //attachment表示以附件方式下载   inline表示在线打开   "Content-Disposition: inline; filename=文件名.mp3"
        // filename表示文件的默认名称，因为网络传输只支持URL编码的相关支付，因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
        // 告知浏览器文件的大小
        response.addHeader("Content-Length", "" + file.length());
        OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
        response.setContentType("application/octet-stream");
        outputStream.write(buffer);
        outputStream.flush();
    }

    /**
     * 前端下载文件方法
     *
     * @param conname
     * @param response
     * @throws IOException
     */
    public static void downLoadFileAll(HttpServletResponse response, HttpServletRequest request, String conname, String filePaths, String zipPath, String filerealnames) throws IOException {


        byte[] buffer = new byte[1024];//将输入流的信息放入到内存中
        File dir = new File(zipPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        /*
         * 创建压缩输出流
         * */
        String filepath = zipPath + "/" + conname + ".zip";
        File file = new File(filepath);//指定压缩文件所在的磁盘位置
        FileOutputStream fous = new FileOutputStream(file);//创建输出流
        //fous.write(buffer);
        ZipOutputStream ouputStream = new ZipOutputStream(fous);//创建压缩文件输出流
        String[] paths = filePaths.split(",");
        String[] filenames = filerealnames.split(",");
        for (int k = 0; k < paths.length; k++) {
            //String path = filePath;
            // path是指想要下载的文件的路径
            System.out.println("文件路径======================="+paths[k]);
            File file2 = new File(paths[k]);
            //log.info(file.getPath());
            // 将文件写入输入流
            FileInputStream fileInputStream = new FileInputStream(file2);
            InputStream fis = new BufferedInputStream(fileInputStream);
//            byte[] buffer2 = new byte[fis.available()];
//            fis.read(buffer2);
            System.out.println("文件名filename=========================" + filenames[k]);
            ZipEntry entry = new ZipEntry(filenames[k]);//参数为附件源文件名
            ouputStream.putNextEntry(entry);
            int nNumber;
            //nNumber = in.read(buffer,0,DEFAULT_BUFFER_SIZE);
            while ((nNumber = fis.read(buffer, 0, 1024)) != -1) {//读取缓存信息，写入到指定文件
                ouputStream.write(buffer, 0, nNumber);
            }

            fis.close();

        }
        try {
            ouputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
//                try {
////                    fin.close();
////                } catch (IOException e) {
////                    e.printStackTrace();
////                }
        try {
            ouputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //InputStream fin = new BufferedInputStream(new FileInputStream(file));
        //ZipInputStream zin = new ZipInputStream(fin);
        OutputStream out = response.getOutputStream();
        try {

            System.out.println("conname=====================" + conname);
            System.out.println("conname.getBytes(\"ISO8859-1\")=====================" + conname.getBytes("ISO8859-1"));
            //addFileName(request, response,conname, new String(conname.getBytes("ISO8859-1"), "utf-8") );
            //response.setHeader("Content-disposition", "attachment; filename=\"" + conname + "\"");
            //response.setContentType("application/download");
            byte[] encodeBytes = getByte(file);
            byte[] decryptEcb = encodeBytes;
            response.reset();
            response.setHeader("Content-Disposition", "attachment;filename=" + conname + ".zip");
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
            response.setContentLength(decryptEcb.length);
            if (true) {
                //OutputStream os = response.getOutputStream();
                out.write(decryptEcb, 0, decryptEcb.length);
                out.close();
                // IOUtils.copy(fin, out);
                /*ouputStream.flush();
                fin.close();
                ouputStream.close();*/


            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static byte[] getByte(File file) throws Exception {
        byte[] bytes = null;
        if (file != null) {
            InputStream is = new FileInputStream(file);
            int length = (int) file.length();
            //当文件的长度超过了int的最大值
            if (length > Integer.MAX_VALUE) {
                System.out.println("this file is max ");
                return null;
            }
            bytes = new byte[length];
            int offset = 0;
            int numRead = 0;
            while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
                offset += numRead;
            }
            //如果得到的字节长度和file实际的长度不一致就可能出错了
            if (offset < bytes.length) {
                System.out.println("file length is error");
                return null;
            }
            is.close();
        }
        return bytes;
    }

    /**
     * 编辑以后保存文件
     *
     * @param jsonObj
     * @param request
     * @param response
     * @throws IOException
     */
    public static void callBackSaveDocument(JSONObject jsonObj, String filePath, String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException {
        /*
         * 当我们关闭编辑窗口后，十秒钟左右onlyoffice会将它存储的我们的编辑后的文件，，此时status = 2，通过request发给我们，我们需要做的就是接收到文件然后回写该文件。
         * */
        /*
         * 定义要与文档存储服务保存的编辑文档的链接。当状态值仅等于2或3时，存在链路。
         * */
        String downloadUri = (String) jsonObj.get("url");
        System.out.println("====文档编辑完成，现在开始保存编辑后的文档，其下载地址为:" + downloadUri);
        //解析得出文件名
        //String fileName = downloadUri.substring(downloadUri.lastIndexOf('/')+1);
//        String fileName = request.getParameter("fileName");
        System.out.println("====下载的文件名:" + fileName);

        URL url = new URL(downloadUri);
        java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
        InputStream stream = connection.getInputStream();
        File savedFile = new File(filePath + "/" + fileName);
        if (null != ((String) jsonObj.get("userdata")) && ((String) jsonObj.get("userdata")).equals("sample userdata")) {
            savedFile = new File(filePath + "/v1" + fileName);
        }


        try (FileOutputStream out = new FileOutputStream(savedFile)) {
            int read;
            final byte[] bytes = new byte[1024];
            while ((read = stream.read(bytes)) != -1) {
                out.write(bytes, 0, read);
            }
            out.flush();
        }
        connection.disconnect();
    }

    /**
     * 发送网路请求查看是否正在编辑
     *
     * @param path
     * @param params
     * @return
     */
    public static String editStatus(String path, String params) {
        OutputStreamWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        HttpURLConnection conn = null;
        try {
            URL url = new URL(path);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            //发送POST请求必须设置为true
            conn.setDoOutput(true);
            conn.setDoInput(true);
            //设置连接超时时间和读取超时时间
            conn.setConnectTimeout(30000);
            conn.setReadTimeout(10000);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Accept", "application/json");
            //获取输出流
            out = new OutputStreamWriter(conn.getOutputStream());
//            String jsonStr = "{\"c\":\"forcesave\", \"key\":\"WpP7m85eNQSEOoepp31oIYVG2oJyJJcvkLdoywgvs1k3ywm3Omuxk4\",\"userdata\":\"sample userdata\"}";
            out.write(params);
            out.flush();
            out.close();
            //取得输入流，并使用Reader读取
            if (200 == conn.getResponseCode()) {

                return IOUtils.toString(conn.getInputStream());


            } else {
                System.out.println("ResponseCode is an error code:" + conn.getResponseCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }

        return "";
    }

    /**
     * 当最后关闭编辑界面后，将编辑时下载的文件删除
     *
     * @param path
     * @param fileName
     */
    public static void deleteTempFile(String path, String fileName) {
        //因为临时存储的文件都添加了v1前缀所以删除文件时需要在文件名测前边加一个v1
        String deleteUrl = path + "/v1" + fileName;
        System.out.println("deleteUrl:" + deleteUrl);
        File file = new File(deleteUrl);
        if (file.exists()) {
            file.delete();
        }
    }

    public static String getFileMd5(File file) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        FileInputStream fis = new FileInputStream(file);
        byte[] dataBytes = new byte[1024];
        int bytesRead;
        while ((bytesRead = fis.read(dataBytes)) != -1) {
            md.update(dataBytes, 0, bytesRead);
        }
        fis.close();
        byte[] mdBytes = md.digest();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < mdBytes.length; i++) {
            sb.append(Integer.toString((mdBytes[i] & 0xff) + 0x100, 16).substring(1));
        }
        return sb.toString();
    }

}
